<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>API接口文档与测试平台</title>
    <style>
        /* 修改 code 元素的样式，使其更清晰可见 */
        code {
            background-color: #e9ecef;
            padding: 0.2rem 0.4rem;
            border-radius: 0.25rem;
            font-size: 0.875em;
            color: #495057;
            border: 1px solid #dee2e6;
        }
        :root {
            --primary-color: #3498db;
            --secondary-color: #2c3e50;
            --success-color: #2ecc71;
            --warning-color: #f39c12;
            --danger-color: #e74c3c;
            --light-bg: #f8f9fa;
            --dark-bg: #343a40;
            --border-color: #eaecef;
        }

        * {
            box-sizing: border-box;
        }

        body {
            background-color: #f5f7f9;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            margin: 0;
            padding: 0;
            line-height: 1.6;
        }

        header {
            background-color: var(--primary-color);
            color: white;
            padding: 1rem 0;
            margin-bottom: 2rem;
        }

        .container {
            width: 90%;
            max-width: 1200px;
            margin: 0 auto;
            padding: 0 1rem;
        }

        .text-center {
            text-align: center;
        }

        h1 {
            font-size: 2rem;
            margin-bottom: 0.5rem;
        }

        .lead {
            font-size: 1.1rem;
            opacity: 0.9;
        }

        .search-bar {
            margin: 1.5rem auto;
            max-width: 600px;
            display: flex;
        }

        .form-control {
            padding: 0.5rem;
            font-size: 1rem;
            border: 1px solid var(--border-color);
            border-radius: 4px;
            flex: 1;
        }

        .btn {
            padding: 0.5rem 1rem;
            font-size: 1rem;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            margin-left: 0.5rem;
        }

        .btn-primary {
            background-color: var(--primary-color);
            color: white;
        }

        .btn-light {
            background-color: #f8f9fa;
            color: #333;
        }

        .filter-buttons {
            margin-bottom: 1rem;
            display: flex;
            flex-wrap: wrap;
            gap: 0.5rem;
        }

        .btn-sm {
            padding: 0.25rem 0.5rem;
            font-size: 0.875rem;
        }

        .btn-outline-secondary {
            background-color: transparent;
            border: 1px solid #6c757d;
            color: #6c757d;
        }

        .btn-outline-secondary.active {
            background-color: #6c757d;
            color: white;
        }

        .method-badge {
            font-size: 0.8em;
            padding: 0.3em 0.6em;
            border-radius: 0.25rem;
            color: white;
            font-weight: bold;
            display: inline-block;
        }

        .method-GET {
            background-color: var(--success-color);
        }

        .method-POST {
            background-color: var(--primary-color);
        }

        .method-PUT {
            background-color: var(--warning-color);
            color: #212529;
        }

        .method-DELETE {
            background-color: var(--danger-color);
        }

        .card {
            background-color: white;
            border: 1px solid var(--border-color);
            border-radius: 8px;
            margin-bottom: 1rem;
            box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
        }

        .controller-card .card-header {
            background-color: var(--secondary-color);
            color: white;
            padding: 1rem;
            border-radius: 8px 8px 0 0;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .card-body {
            padding: 1rem;
        }

        .d-flex {
            display: flex;
        }

        .justify-content-between {
            justify-content: space-between;
        }

        .align-items-center {
            align-items: center;
        }

        .mb-3 {
            margin-bottom: 1rem;
        }

        .api-card {
            border: 1px solid var(--border-color);
            border-radius: 4px;
            padding: 1rem;
            margin-bottom: 1rem;
            background-color: white;
        }

        code {
            background-color: #f8f9fa;
            padding: 0.2rem 0.4rem;
            border-radius: 0.25rem;
            font-size: 0.875em;
        }

        .btn-outline-primary {
            border: 1px solid var(--primary-color);
            color: var(--primary-color);
            background-color: transparent;
        }

        .btn-outline-primary:hover {
            background-color: var(--primary-color);
            color: white;
        }

        .btn-success {
            background-color: var(--success-color);
            color: white;
        }

        .collapse {
            display: none;
        }

        .collapse.show {
            display: block;
        }

        table {
            width: 100%;
            border-collapse: collapse;
            margin: 1rem 0;
        }

        th, td {
            padding: 0.5rem;
            text-align: left;
            border-bottom: 1px solid var(--border-color);
        }

        th {
            background-color: #f8f9fa;
        }

        .table-striped tr:nth-child(even) {
            background-color: #f8f9fa;
        }

        .test-panel {
            background-color: var(--light-bg);
            border-radius: 8px;
            padding: 1.5rem;
            margin-top: 1rem;
        }

        .form-label {
            display: block;
            margin-bottom: 0.5rem;
            font-weight: bold;
        }

        .form-control-sm {
            padding: 0.25rem 0.5rem;
            font-size: 0.875rem;
        }

        .nav-tabs {
            display: flex;
            border-bottom: 1px solid var(--border-color);
            margin-bottom: 1rem;
        }

        .nav-link {
            padding: 0.5rem 1rem;
            border: none;
            background: none;
            cursor: pointer;
            border-bottom: 3px solid transparent;
            color: #6c757d;
        }

        .nav-link.active {
            border-bottom: 3px solid var(--primary-color);
            color: var(--primary-color);
            font-weight: 500;
        }

        .tab-content {
            margin-bottom: 1rem;
        }

        .tab-pane {
            display: none;
        }

        .tab-pane.show {
            display: block;
        }

        .response-area {
            background-color: #f8f9fa;
            border-radius: 6px;
            padding: 1rem;
            margin-top: 1rem;
            max-height: 300px;
            overflow-y: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9em;
            display: none;
        }

        .response-area.show {
            display: block;
        }

        footer {
            margin-top: 3rem;
            padding: 1.5rem 0;
            background-color: var(--dark-bg);
            color: white;
            text-align: center;
        }

        a {
            color: #80bdff;
            text-decoration: none;
        }

        a:hover {
            color: #cce5ff;
            text-decoration: underline;
        }

        .loading-overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(255, 255, 255, 0.8);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 9999;
        }

        .spinner {
            display: inline-block;
            width: 2rem;
            height: 2rem;
            border: 4px solid rgba(0, 0, 0, 0.1);
            border-radius: 50%;
            border-top-color: #007bff;
            animation: spin 0.8s ease-in-out infinite;
        }

        @keyframes spin {
            to { transform: rotate(360deg); }
        }

        @media (max-width: 768px) {
            .d-flex {
                flex-direction: column;
            }

            .search-bar {
                flex-direction: column;
            }

            .btn {
                margin-left: 0;
                margin-top: 0.5rem;
            }
        }
    </style>
</head>
<body>
<header class="bg-primary text-white py-4 mb-5">
    <div class="container">
        <h1 class="display-5 fw-bold">API接口文档与测试平台</h1>
        <p class="lead">总接口数: <span id="totalApis">0</span> 个 | 生成时间: <span id="generatedTime"></span></p>

        <!-- 搜索框 -->
        <div class="search-bar input-group mt-3 w-75 mx-auto">
            <input type="text" id="apiSearch" class="form-control form-control-lg" placeholder="搜索接口路径或描述...">
            <button class="btn btn-light" type="button" id="searchButton">
                🔍 搜索
            </button>
        </div>
    </div>
</header>

<div class="loading-overlay" id="loadingOverlay">
    <div class="text-center">
        <div class="spinner"></div>
        <p class="mt-3">正在加载API数据...</p>
    </div>
</div>

<div class="container mb-5 api-test-container" id="apiContainer" style="display: none;">
    <!-- 方法类型筛选 -->
    <div class="filter-buttons d-flex flex-wrap">
        <button class="btn btn-sm btn-outline-secondary me-2 mb-2 active" data-filter="all">全部</button>
        <button class="btn btn-sm method-GET me-2 mb-2" data-filter="GET">GET</button>
        <button class="btn btn-sm method-POST me-2 mb-2" data-filter="POST">POST</button>
        <button class="btn btn-sm method-PUT me-2 mb-2" data-filter="PUT">PUT</button>
        <button class="btn btn-sm method-DELETE me-2 mb-2" data-filter="DELETE">DELETE</button>
    </div>

    <!-- 控制器列表 -->
    <div class="controller-list" id="controllerList">
        <!-- 内容将通过JavaScript动态生成 -->
    </div>
</div>

<footer class="bg-dark py-4 mt-5">
    <div class="container text-center text-white">
        <p class="mb-0">API文档自动生成工具 | <a href="/api-docs/json">查看原始JSON数据</a></p>
    </div>
</footer>

<script>
    // 全局变量存储API数据
    let apiData = null;
    let totalApis = 0;

    // 页面加载完成后初始化
    document.addEventListener('DOMContentLoaded', function() {
        // 显示加载界面
        document.getElementById('loadingOverlay').style.display = 'flex';

        // 从后端获取API数据
        fetch('/api-docs/json')
            .then(response => response.json())
            .then(data => {
                apiData = data;
                renderApiDocumentation();
                document.getElementById('loadingOverlay').style.display = 'none';
                document.getElementById('apiContainer').style.display = 'block';
            })
            .catch(error => {
                console.error('获取API数据失败:', error);
                document.getElementById('loadingOverlay').innerHTML = `
                    <div class="text-center">
                        <div style="background-color: #f8d7da; color: #721c24; padding: 1rem; border-radius: 4px; margin: 1rem;">
                            <h4>加载失败</h4>
                            <p>无法从服务器获取API数据</p>
                            <button class="btn btn-primary mt-2" onclick="location.reload()">重新加载</button>
                        </div>
                    </div>
                `;
            });

        // 搜索功能
        const searchInput = document.getElementById('apiSearch');
        const searchButton = document.getElementById('searchButton');

        function performSearch() {
            const searchTerm = searchInput.value.toLowerCase().trim();
            const apiCards = document.querySelectorAll('.api-card');

            apiCards.forEach(card => {
                const path = card.getAttribute('data-path') || '';
                const desc = card.getAttribute('data-desc') || '';

                if (path.toLowerCase().includes(searchTerm) || desc.toLowerCase().includes(searchTerm)) {
                    card.style.display = '';
                } else {
                    card.style.display = 'none';
                }
            });
        }

        searchButton.addEventListener('click', performSearch);
        searchInput.addEventListener('keyup', function(e) {
            if (e.key === 'Enter') {
                performSearch();
            }
        });
    });

    // 渲染API文档
    function renderApiDocumentation() {
        const controllerList = document.getElementById('controllerList');
        controllerList.innerHTML = '';
        totalApis = 0;

        // 更新总接口数和生成时间
        document.getElementById('generatedTime').textContent = new Date().toLocaleString();

        // 遍历控制器
        apiData.controllers.forEach((controller, controllerIndex) => {
            totalApis += controller.apis ? controller.apis.length : 0;

            const controllerCard = document.createElement('div');
            controllerCard.className = 'card mb-4 controller-card';

            controllerCard.innerHTML = `
                <div class="card-header bg-secondary text-white d-flex justify-content-between align-items-center">
                    <h2 class="h4 mb-0">
                        📦 ${controller.className}
                        <small class="ms-3 text-black-50" style="font-size: 0.8rem;">
                            基础路径: <code>${controller.basePath || '/'}</code>
                        </small>
                    </h2>
                    <span style="background-color: #f8f9fa; color: #212529; padding: 0.25rem 0.5rem; border-radius: 4px;">${controller.apis ? controller.apis.length : 0} 个接口</span>
                </div>
                <div class="card-body">
                    ${controller.apis && controller.apis.length > 0 ?
                controller.apis.map((api, apiIndex) => renderApiCard(api, controllerIndex, apiIndex)).join('') :
                '<div style="background-color: #d1ecf1; color: #0c5460; padding: 1rem; border-radius: 4px;">该控制器下没有接口信息</div>'
            }
                </div>
            `;

            controllerList.appendChild(controllerCard);
        });

        // 更新总接口数
        document.getElementById('totalApis').textContent = totalApis;

        // 绑定事件
        bindEvents();
    }

    // 渲染API卡片
    function renderApiCard(api, controllerIndex, apiIndex) {
        const hasParams = api.parameters && api.parameters.length > 0;
        const paramInputs = hasParams ? renderParameterInputs(api.parameters, controllerIndex, apiIndex) : '';

        return `
            <div class="api-card card mb-3" data-method="${api.httpMethod}" data-path="${api.path}" data-desc="${api.description || ''}">
                <div class="card-body">
                    <div class="d-flex justify-content-between align-items-center mb-3">
                        <h3 class="h5 mb-0">
                            <span class="method-badge method-${api.httpMethod}">${api.httpMethod}</span>
                            <code class="ms-2">${api.path}</code>
                        </h3>
                        <div>
                            <button class="btn btn-sm btn-outline-primary me-2" data-toggle="collapse"
                                data-target="#apiDetails${controllerIndex}${apiIndex}">
                                ▼ 详情
                            </button>
                            <button class="btn btn-sm btn-success test-btn" data-toggle="collapse"
                                data-target="#testPanel${controllerIndex}${apiIndex}">
                                ⚡ 测试
                            </button>
                        </div>
                    </div>

                    ${api.description ? `<p class="card-text"><strong>描述:</strong> ${api.description}</p>` : ''}
                    ${api.notes ? `<p class="card-text"><strong>备注:</strong> ${api.notes}</p>` : ''}
                    <p class="card-text">
                        <strong>返回类型:</strong> <code>${api.returnType}</code>
                    </p>

                    <!-- 接口详情（可折叠） -->
                    <div id="apiDetails${controllerIndex}${apiIndex}" class="collapse mt-3">
                        <h4 class="h6">参数列表:</h4>
                        ${hasParams ? renderParameterTable(api.parameters) : '<p class="text-muted">无参数</p>'}
                    </div>

                    <!-- 测试面板 -->
                    <div id="testPanel${controllerIndex}${apiIndex}" class="test-panel collapse mt-3">
                        <h4 class="h6 mb-3">⚡ 接口测试</h4>

                        <div style="background-color: #f8f9fa; padding: 0.5rem; border-radius: 4px; margin-bottom: 1rem; word-break: break-all;">
                            <strong>请求URL:</strong> <span class="url-text"></span>
                        </div>

                        <div class="nav-tabs mb-3" role="tablist">
                            ${hasParams ? '<button class="nav-link active" data-toggle="tab" ' +
            `data-target="#params${controllerIndex}${apiIndex}" type="button" role="tab">参数</button>` : ''}
                            <button class="nav-link ${!hasParams ? 'active' : ''}" data-toggle="tab"
                                data-target="#headers${controllerIndex}${apiIndex}" type="button" role="tab">请求头</button>
                            ${api.httpMethod === 'POST' || api.httpMethod === 'PUT' ?
            '<button class="nav-link" data-toggle="tab" ' +
            `data-target="#body${controllerIndex}${apiIndex}" type="button" role="tab">请求体</button>` : ''}
                        </div>

                        <div class="tab-content">
                            ${hasParams ? `
                            <div class="tab-pane fade show active" id="params${controllerIndex}${apiIndex}" role="tabpanel">
                                ${paramInputs}
                            </div>
                            ` : ''}

                            <div class="tab-pane fade ${!hasParams ? 'show active' : ''}" id="headers${controllerIndex}${apiIndex}" role="tabpanel">
                                <div class="header-fields">
                                    <div class="header-input mb-2 d-flex align-items-center">
                                        <input type="text" class="form-control form-control-sm me-2 header-name" placeholder="Header名称" value="Content-Type" style="width: 40%;">
                                        <input type="text" class="form-control form-control-sm header-value" placeholder="Header值" value="application/json" style="width: 55%;">
                                        <button class="btn btn-sm" style="background-color: #f8d7da; color: #721c24; margin-left: 0.5rem;" type="button">
                                            ×
                                        </button>
                                    </div>
                                </div>
                                <button class="btn btn-sm btn-outline-primary mt-2 add-header-btn">
                                    + 添加请求头
                                </button>
                            </div>

                            ${api.httpMethod === 'POST' || api.httpMethod === 'PUT' ? `
                            <div class="tab-pane fade" id="body${controllerIndex}${apiIndex}" role="tabpanel">
                                <div class="mb-2">
                                    <label class="form-label">请求体格式</label>
                                    <select class="form-select form-select-sm body-type-select" style="width: 100%; padding: 0.25rem;">
                                        <option value="json" selected>JSON</option>
                                        <option value="form">表单数据</option>
                                    </select>
                                </div>

                                <div class="json-body">
                                    <label class="form-label">JSON 数据</label>
                                    <textarea class="form-control json-body-text" rows="5" placeholder='{"key": "value"}' style="width: 100%;"></textarea>
                                </div>

                                <div class="form-body" style="display: none;">
                                    <div class="form-fields">
                                        <div class="form-input mb-2 d-flex align-items-center">
                                            <input type="text" class="form-control form-control-sm me-2 form-field-name" placeholder="参数名" style="width: 40%;">
                                            <input type="text" class="form-control form-control-sm form-field-value" placeholder="参数值" style="width: 55%;">
                                            <button class="btn btn-sm" style="background-color: #f8d7da; color: #721c24; margin-left: 0.5rem;" type="button">
                                                ×
                                            </button>
                                        </div>
                                    </div>
                                    <button class="btn btn-sm btn-outline-primary mt-2 add-form-field-btn">
                                        + 添加表单字段
                                    </button>
                                </div>
                            </div>
                            ` : ''}
                        </div>

                        <div class="d-flex justify-content-between align-items-center mt-3">
                            <div>
                                <button class="btn btn-sm btn-primary test-send-btn"
                                    data-method="${api.httpMethod}"
                                    data-base-path="${apiData.controllers[controllerIndex].basePath || ''}"
                                    data-api-path="${api.path}">
                                    📤 发送请求
                                </button>
                                <button class="btn btn-sm btn-outline-secondary test-clear-btn">
                                    🧹 清除
                                </button>
                            </div>
                            <div class="test-status" style="display: none;">
                                <span class="spinner"></span>
                                <span>请求中...</span>
                            </div>
                        </div>

                        <div class="response-area mt-3">
                            <div class="d-flex justify-content-between align-items-center mb-2">
                                <h5 class="mb-0">响应结果</h5>
                                <div class="response-meta"></div>
                            </div>
                            <div class="response-content"></div>
                        </div>
                    </div>
                </div>
            </div>
        `;
    }

    // 渲染参数表格
    function renderParameterTable(parameters) {
        return `
            <div class="table-responsive">
                <table class="table table-striped table-sm">
                    <thead>
                        <tr>
                            <th>参数名</th>
                            <th>类型</th>
                            <th>位置</th>
                            <th>是否必须</th>
                            <th>默认值</th>
                            <th>描述</th>
                        </tr>
                    </thead>
                    <tbody>
                        ${parameters.map(param => `
                            <tr>
                                <td>${param.name}</td>
                                <td>${param.type}</td>
                                <td>
                                    <span style="font-size: 0.7em; padding: 0.2em 0.4em; border-radius: 0.2rem; display: inline-block;
                                        background-color: ${param.parameterType === 'QUERY' ? '#e3f2fd' :
            param.parameterType === 'PATH' ? '#e8f5e9' :
                param.parameterType === 'BODY' ? '#fff8e1' :
                    param.parameterType === 'HEADER' ? '#f3e5f5' : '#ffebee'};
                                        color: ${param.parameterType === 'QUERY' ? '#0d47a1' :
            param.parameterType === 'PATH' ? '#1b5e20' :
                param.parameterType === 'BODY' ? '#ff8f00' :
                    param.parameterType === 'HEADER' ? '#4a148c' : '#b71c1c'}">
                                        ${param.parameterType}
                                    </span>
                                </td>
                                <td>${param.required ? '<span style="color: var(--danger-color); font-weight: bold;">✓</span>' : ''}</td>
                                <td>${param.defaultValue || '-'}</td>
                                <td>${param.description || '-'}</td>
                            </tr>
                        `).join('')}
                    </tbody>
                </table>
            </div>
        `;
    }

    // 渲染参数输入框
    function renderParameterInputs(parameters, controllerIndex, apiIndex) {
        return parameters.map(param => {
            console.log(param.type.toLowerCase())
            // 文件类型
            if (param.type && param.type.toLowerCase() === 'multipartfile') {
                return `
                <div class="param-input">
                    <label class="form-label">${param.name} (文件)</label>
                    <input type="file"
                           class="form-control form-control-sm file-param"
                           data-param-type="FILE"
                           data-param-name="${param.name}"
                           style="width:100%;">
                </div>`;
            }
            // 普通类型保持原样
            const inputType = (param.type === 'Long' || param.type === 'Integer') ? 'number' : 'text';
            return `
            <div class="param-input">
                <label class="form-label">${param.name} (${param.parameterType})</label>
                <input type="${inputType}"
                       class="form-control form-control-sm"
                       data-param-type="${param.parameterType}"
                       data-param-name="${param.name}"
                       value="${param.defaultValue || ''}"
                       placeholder="${param.description || ''}"
                       style="width:100%;">
            </div>`;
        }).join('');
    }
    // 绑定事件
    function bindEvents() {
        // 方法类型筛选
        const filterButtons = document.querySelectorAll('.filter-buttons button');
        filterButtons.forEach(button => {
            button.addEventListener('click', function() {
                const filter = this.getAttribute('data-filter');
                const apiCards = document.querySelectorAll('.api-card');

                apiCards.forEach(card => {
                    if (filter === 'all' || card.getAttribute('data-method') === filter) {
                        card.style.display = '';
                    } else {
                        card.style.display = 'none';
                    }
                });

                // 更新按钮样式
                filterButtons.forEach(btn => btn.classList.remove('active'));
                this.classList.add('active');
            });
        });

        // 折叠面板功能
        document.querySelectorAll('[data-toggle="collapse"]').forEach(button => {
            button.addEventListener('click', function() {
                const targetId = this.getAttribute('data-target');
                const target = document.querySelector(targetId);
                if (target) {
                    target.classList.toggle('show');
                }
            });
        });

        // 标签页切换
        document.querySelectorAll('[data-toggle="tab"]').forEach(button => {
            button.addEventListener('click', function() {
                const targetId = this.getAttribute('data-target');
                const parent = this.closest('.test-panel');

                // 隐藏所有标签页内容
                parent.querySelectorAll('.tab-pane').forEach(pane => {
                    pane.classList.remove('show', 'active');
                });

                // 移除所有标签链接的active类
                parent.querySelectorAll('.nav-link').forEach(link => {
                    link.classList.remove('active');
                });

                // 显示目标标签页内容
                const target = document.querySelector(targetId);
                if (target) {
                    target.classList.add('show', 'active');
                }

                // 给当前标签链接添加active类
                this.classList.add('active');
            });
        });

        // 添加请求头字段
        document.querySelectorAll('.add-header-btn').forEach(button => {
            button.addEventListener('click', function() {
                const headerFields = this.previousElementSibling;
                const newHeader = headerFields.querySelector('.header-input').cloneNode(true);

                // 清空输入值
                newHeader.querySelectorAll('input').forEach(input => input.value = '');

                // 添加删除事件
                newHeader.querySelector('.btn').addEventListener('click', function() {
                    this.parentElement.remove();
                });

                headerFields.appendChild(newHeader);
            });
        });

        // 添加表单字段
        document.querySelectorAll('.add-form-field-btn').forEach(button => {
            button.addEventListener('click', function() {
                const formFields = this.previousElementSibling;
                const newField = formFields.querySelector('.form-input').cloneNode(true);

                // 清空输入值
                newField.querySelectorAll('input').forEach(input => input.value = '');

                // 添加删除事件
                newField.querySelector('.btn').addEventListener('click', function() {
                    this.parentElement.remove();
                });

                formFields.appendChild(newField);
            });
        });

        // 请求体格式切换
        document.querySelectorAll('.body-type-select').forEach(select => {
            select.addEventListener('change', function() {
                const parent = this.closest('.tab-pane');
                const jsonBody = parent.querySelector('.json-body');
                const formBody = parent.querySelector('.form-body');

                if (this.value === 'json') {
                    jsonBody.style.display = 'block';
                    formBody.style.display = 'none';
                } else {
                    jsonBody.style.display = 'none';
                    formBody.style.display = 'block';
                }
            });
        });

        // 发送测试请求
        document.querySelectorAll('.test-send-btn').forEach(button => {
            button.addEventListener('click', function() {
                const method = this.getAttribute('data-method');
                const basePath = this.getAttribute('data-base-path');
                const apiPath = this.getAttribute('data-api-path');
                const testPanel = this.closest('.test-panel');
                const testStatus = testPanel.querySelector('.test-status');
                const responseArea = testPanel.querySelector('.response-area');
                const responseContent = testPanel.querySelector('.response-content');
                const responseMeta = testPanel.querySelector('.response-meta');
                const urlText = testPanel.querySelector('.url-text');

                // 显示加载状态
                testStatus.style.display = 'block';
                responseArea.classList.remove('show');

                // 收集参数
                const params = {};
                testPanel.querySelectorAll('[data-param-type]').forEach(input => {
                    if (input.value.trim() !== '') {
                        const paramType = input.getAttribute('data-param-type');
                        const paramName = input.getAttribute('data-param-name');
                        params[paramName] = input.value;
                    }
                });

                // 收集请求头
                const headers = {};
                testPanel.querySelectorAll('.header-input').forEach(headerInput => {
                    const keyInput = headerInput.querySelector('.header-name');
                    const valueInput = headerInput.querySelector('.header-value');

                    if (keyInput.value.trim() !== '' && valueInput.value.trim() !== '') {
                        headers[keyInput.value] = valueInput.value;
                    }
                });

                // 收集请求体
                let requestBody = null;
                if (method === 'POST' || method === 'PUT') {
                    const bodyType = testPanel.querySelector('.body-type-select');

                    if (bodyType && bodyType.value === 'json') {
                        const jsonBody = testPanel.querySelector('.json-body-text');
                        if (jsonBody && jsonBody.value.trim() !== '') {
                            try {
                                requestBody = JSON.parse(jsonBody.value);
                            } catch (e) {
                                alert('JSON格式错误: ' + e.message);
                                testStatus.style.display = 'none';
                                return;
                            }
                        }
                    } else {
                        requestBody = {};
                        testPanel.querySelectorAll('.form-input').forEach(formInput => {
                            const keyInput = formInput.querySelector('.form-field-name');
                            const valueInput = formInput.querySelector('.form-field-value');

                            if (keyInput.value.trim() !== '' && valueInput.value.trim() !== '') {
                                requestBody[keyInput.value] = valueInput.value;
                            }
                        });
                    }
                }

                // 构建完整URL路径
                let targetUrl = apiPath;

                // 处理路径参数
                if (params) {
                    for (const [key, value] of Object.entries(params)) {
                        if (targetUrl.includes(`{${key}}`)) {
                            targetUrl = targetUrl.replace(`{${key}}`, encodeURIComponent(value));
                            delete params[key];
                        }
                    }
                }

                // 添加查询参数
                let finalUrl = targetUrl;
                if ((method === 'GET' || method === 'DELETE') && Object.keys(params).length > 0) {
                    const queryParams = new URLSearchParams();
                    for (const [key, value] of Object.entries(params)) {
                        queryParams.append(key, value);
                    }
                    finalUrl += '?' + queryParams.toString();
                }

                urlText.textContent = finalUrl;

                // 准备请求选项
                const requestOptions = {
                    method: method,
                    headers: {
                        'Content-Type': 'application/json',
                        ...headers
                    }
                };

                // 添加请求体（对于非GET/DELETE请求）
                if ((method === 'POST' || method === 'PUT') && requestBody) {
                    requestOptions.body = JSON.stringify(requestBody);
                }

                // 直接发送请求到目标接口
                fetch(finalUrl, requestOptions)
                    .then(response => {
                        const status = response.status;
                        const statusClass = `status-${Math.floor(status/100)}xx`;
                        responseMeta.innerHTML = `<span style="padding: 0.3rem 0.6rem; border-radius: 4px; font-weight: bold;
                            ${status >= 200 && status < 300 ? 'background-color: #d4edda; color: #155724;' :
                            status >= 400 && status < 500 ? 'background-color: #f8d7da; color: #721c24;' :
                                'background-color: #fff3cd; color: #856404;'}">${status} ${response.statusText}</span>`;

                        // 尝试解析JSON响应
                        const contentType = response.headers.get('content-type');
                        if (contentType && contentType.includes('application/json')) {
                            return response.json();
                        } else {
                            return response.text();
                        }
                    })
                    .then(data => {
                        // 隐藏加载状态
                        testStatus.style.display = 'none';

                        // 显示响应结果
                        if (typeof data === 'object') {
                            responseContent.innerHTML = syntaxHighlight(JSON.stringify(data, null, 2));
                        } else {
                            responseContent.textContent = data;
                        }
                        responseArea.classList.add('show');
                    })
                    .catch(error => {
                        // 隐藏加载状态
                        testStatus.style.display = 'none';

                        // 显示错误信息
                        responseContent.textContent = '请求失败: ' + error.message;
                        responseArea.classList.add('show');
                    });
            });
        });

        // JSON语法高亮
        function syntaxHighlight(json) {
            if (typeof json !== 'string') {
                json = JSON.stringify(json, undefined, 2);
            }

            json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');

            return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
                let cls = 'number';
                if (/^"/.test(match)) {
                    if (/:$/.test(match)) {
                        cls = 'key';
                    } else {
                        cls = 'string';
                    }
                } else if (/true|false/.test(match)) {
                    cls = 'boolean';
                } else if (/null/.test(match)) {
                    cls = 'null';
                }
                return '<span style="color: ' +
                    (cls === 'key' ? '#905' :
                        cls === 'string' ? '#690' :
                            cls === 'number' || cls === 'boolean' || cls === 'null' ? '#07a' : '#000') +
                    '">' + match + '</span>';
            });
        }

        // 初始化删除按钮事件
        document.querySelectorAll('.header-fields .btn, .form-fields .btn').forEach(button => {
            button.addEventListener('click', function() {
                this.parentElement.remove();
            });
        });

        // 清除按钮事件
        document.querySelectorAll('.test-clear-btn').forEach(button => {
            button.addEventListener('click', function() {
                const testPanel = this.closest('.test-panel');
                testPanel.querySelectorAll('input').forEach(input => input.value = '');
                testPanel.querySelectorAll('textarea').forEach(textarea => textarea.value = '');
                testPanel.querySelector('.response-area').classList.remove('show');
            });
        });
    }
</script>
</body>
</html>
